/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import * as path from 'path';
import {
  DefaultFilesystemSnapshotGenerator
} from '../../../../../src/base/internal/snapshot/generator/default-filesystem-snapshot-generator';
import { DirectorySnapshot } from '../../../../../src/base/internal/snapshot/core/directory-snapshot';
import { FileSnapshot } from '../../../../../src/base/internal/snapshot/core/file-snapshot';
import { FileContentHasher } from '../../../../../src/base/internal/snapshot/util/file-hasher';
import { readFile } from '../../../../../src/base/util/file-util';
import { BasicFileSnapshot } from '../../../../../src/base/internal/snapshot/core/filesystem-snapshot';
import { FileType } from '../../../../../src/base/internal/snapshot/util/file-type';
import { FileMetaData } from '../../../../../src/base/internal/snapshot/util/file-metadata';

describe('test snapshot generator', () => {
  const snapshotGenerator = new DefaultFilesystemSnapshotGenerator(new FileContentHasher());
  const testDir = path.resolve('test/resource/snapshot/testdir');

  /**
   * 测试生成 FileSnapshot
   */
  test('test generator file snapshot', () => {
    const testFile = path.join(testDir, 'test1.txt');
    const testFileSnapshot = snapshotGenerator.snapshot(testFile);
    expect(testFileSnapshot instanceof FileSnapshot);
    if (testFileSnapshot !== undefined) {
      expect(testFileSnapshot.hashValue).toBe('73d36d3fcf23c3885f33df27b18e974b');
    }
  });

  /**
   * 测试生成 DirectorySnapshot
   */
  test('test generator directory snapshot', () => {
    const testDirSnapshot = snapshotGenerator.snapshot(testDir);
    expect(testDirSnapshot instanceof DirectorySnapshot);
    if (testDirSnapshot !== undefined) {
      expect(testDirSnapshot.hashValue).toBe('c0baa50b6d3939d35b60a766b795e3a6');
      if (testDirSnapshot instanceof DirectorySnapshot) {
        expect(testDirSnapshot.children.length).toBe(3);
      }
    }
  });

  /**
   * 测试反序列化单个 FileSnapshot json string
   */
  test('test load file snapshot json', async () => {
    const fileSnapshotJsonFile = path.resolve('test/resource/snapshot/file-snapshot.json');
    const buffer = await readFile(fileSnapshotJsonFile);
    const jsonString = buffer.toString();
    const basicFileSnapshot = snapshotGenerator.loadSnapshotFromJson(jsonString);

    expect(basicFileSnapshot instanceof FileSnapshot);
    const fileSnapshot = basicFileSnapshot as FileSnapshot;
    expect(fileSnapshot.hashValue).toBe('9fcfaa8a916bfb3d1dd685c0ba149ea9');
    expect(fileSnapshot.name).toBe('1.txt');
    expect(fileSnapshot.type).toBe('file');
    expect(fileSnapshot.fileMetaData.size).toBe(13);
    expect(fileSnapshot.fileMetaData.lastModifiedTime).toBe(1661499439641);
  });

  /**
   * 测试反序列化单个 DirectorySnapshot json string
   */
  test('test load directory snapshot json', async () => {
    const directorySnapshotJsonFile = path.resolve('test/resource/snapshot/directory-snapshot.json');
    const buffer = await readFile(directorySnapshotJsonFile);
    const jsonString = buffer.toString();
    const basicFileSnapshot = snapshotGenerator.loadSnapshotFromJson(jsonString);

    expect(basicFileSnapshot instanceof DirectorySnapshot);
    const aaaDirectorySnapshot = basicFileSnapshot as DirectorySnapshot;
    expect(aaaDirectorySnapshot.hashValue).toBe('620e943fa31648a0011510e3753d3e10');
    expect(aaaDirectorySnapshot.name).toBe('aaa');
    expect(aaaDirectorySnapshot.type).toBe('directory');
    expect(aaaDirectorySnapshot.children.length).toBe(2);

    const txt1 = aaaDirectorySnapshot.children[0];
    expect(txt1.hashValue).toBe('9fcfaa8a916bfb3d1dd685c0ba149ea9');
    expect(txt1.name).toBe('1.txt');
    expect(txt1.type).toBe('file');

    const bbDirectory = aaaDirectorySnapshot.children[1];
    expect(bbDirectory.hashValue).toBe('3ee8161409efb54b832c44058d3a1a73');
    expect(bbDirectory.name).toBe('bb');
    expect(bbDirectory.type).toBe('directory');

    expect(bbDirectory instanceof DirectorySnapshot);
    const bbDirectorySnapshot = bbDirectory as DirectorySnapshot;
    expect(bbDirectorySnapshot.children.length).toBe(2);

    const ccDirectory = bbDirectorySnapshot.children[1];
    expect(ccDirectory.hashValue).toBe('631440cc115125b8ae2b0f6e11a9fdca');
    expect(ccDirectory.name).toBe('cc');
    expect(ccDirectory.type).toBe('directory');

    expect(ccDirectory instanceof DirectorySnapshot);
    const ccDirectorySnapshot = ccDirectory as DirectorySnapshot;
    expect(ccDirectorySnapshot.children.length).toBe(2);
    const c2txt = ccDirectorySnapshot.children[1] as FileSnapshot;
    expect(c2txt.hashValue).toBe('091ce6750502a38b57df7a9dbf9bfe9e');
    expect(c2txt.name).toBe('c2.txt');
    expect(c2txt.path).toBe('C:\\Users\\Desktop\\aaa\\bb\\cc\\c2.txt');
    expect(c2txt.fileMetaData.size).toBe(10);
    expect(c2txt.fileMetaData.lastModifiedTime).toBe(1661499419131);
  });

  /**
   * 测试 Map<string,BasicFileSnapshot> 类型的序列化和反序列化
   */
  test('test serialize and deserialize of  snapshot map', () => {
    const map = new Map<string, BasicFileSnapshot>();
    const fileSnapshot1 = new FileSnapshot('file1.ts', 'path:/file1', FileType.FILE, false,
      new FileMetaData(100, 123456));
    fileSnapshot1.hashValue = 'file1hash';
    const fileSnapshot2 = new FileSnapshot('file2.ts', 'path:/file2', FileType.FILE, false,
      new FileMetaData(120, 123457));
    fileSnapshot2.hashValue = 'file2hash';
    const directorySnapshot1 = new DirectorySnapshot('dir1', 'path:/dir1', FileType.DIRECTORY, false);
    directorySnapshot1.hashValue = 'dir1hash';
    directorySnapshot1.children.push(fileSnapshot2);
    map.set('fileSnapshot1', fileSnapshot1);
    map.set('directorySnapshot1', directorySnapshot1);

    // 序列化 map 为 json string
    const jsonStr = snapshotGenerator.serializeSnapshotToJson(map);

    // 直接反序列化 json string 为 map
    const deserializedMap = snapshotGenerator.loadSnapshotCacheFromJson(jsonStr);
    expect(deserializedMap !== undefined);
    if (deserializedMap !== undefined) {
      const deserializedFileSnapshot1 = deserializedMap.get('fileSnapshot1');
      expect(deserializedFileSnapshot1 !== undefined);
      if (deserializedFileSnapshot1 !== undefined) {
        const dfs1 = deserializedFileSnapshot1 as FileSnapshot;
        expect(dfs1.hashValue).toBe('file1hash');
        expect(dfs1.name).toBe('file1.ts');
        expect(dfs1.path).toBe('path:/file1');
        expect(dfs1.fileMetaData.size).toBe(100);
        expect(dfs1.fileMetaData.lastModifiedTime).toBe(123456);
      }

      const deserializedDirectorySnapshot1 = deserializedMap.get('directorySnapshot1');
      expect(deserializedDirectorySnapshot1 !== undefined);
      if (deserializedDirectorySnapshot1 !== undefined) {
        const dds1 = deserializedDirectorySnapshot1 as DirectorySnapshot;
        expect(dds1.name).toBe('dir1');
        expect(dds1.hashValue).toBe('dir1hash');
        expect(dds1.children.length).toBe(1);

        const dfs2 = dds1.children[0] as FileSnapshot;
        expect(dfs2.name).toBe('file2.ts');
        expect(dfs2.hashValue).toBe('file2hash');
        expect(dfs2.fileMetaData.size).toBe(120);
        expect(dfs2.fileMetaData.lastModifiedTime).toBe(123457);
      }
    }
  });
});
